home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / tn3270 / vmxfer.c < prev    next >
Text File  |  1992-04-17  |  36KB  |  1,483 lines

  1. /*
  2.  *  tn3270 for the Macintosh Source Code
  3.  *  Brown University Computing and Information Services
  4.  *  Version 2.4d7  April, 1992
  5.  *  Copyright (c) 1988, 1989, 1990, 1991, 1992 by Brown University and by
  6.  *  Peter John DiCamillo.
  7.  *
  8.  *  Permission is granted to any individual or institution to use, copy,
  9.  *  or redistribute the binary version of this software and its
  10.  *  documentation provided this notice and the copyright notices are
  11.  *  retained.  Permission is granted to any individual or non-profit
  12.  *  institution to use, copy, modify, or redistribute the source files
  13.  *  of this software provided this notice and the copyright notices are
  14.  *  retained.  This software may not be distributed for profit, either
  15.  *  in original form or in derivative works, nor can the source be
  16.  *  distributed to other than an individual or a non-profit institution.
  17.  *  Any  individual or group interested in seeing and/or using these
  18.  *  source files but who are prevented from doing so by the above
  19.  *  constraints should contact Don Wolfe, Assistant Vice-President for
  20.  *  Computer Systems at Brown University, (401) 863-7250, for possible
  21.  *  software licensing of the source developed at Brown.
  22.  *
  23.  *  Brown University and Peter John DiCamillo make no representations
  24.  *  about the suitability of this software for any purpose.
  25.  *
  26.  *  BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
  27.  *  EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  28.  *  INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  29.  *  WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  30.  *
  31.  */
  32.  
  33. #if !defined(USEDUMP)
  34.     #include "maclib.h"
  35.     #include "termdef.h"
  36.     #include "tn3270funcs.h"
  37.     #include "globals.h"
  38. #else
  39.     #pragma load "tn3270DumpFile"
  40. #endif
  41.  
  42. #pragma segment vmxfer
  43.  
  44. #define    IAC 255                /* Telnet: interpret as command: */
  45.  
  46. vmprt prtinfo = {    /* defaults if VMPR 128 resource is not present */
  47.     4,                            /* fontnum */
  48.     10,                            /* pointsize */
  49.     12,                            /* leading */
  50.     132,                        /* linewidth */
  51.     4,                            /* tabsize */
  52.     57,                            /* pagelength */
  53.     59,                            /* pagelencc */
  54.     14,                            /* top */
  55.     2,                            /* headmarg */
  56.     12,                            /* left */
  57.     0,                            /* leftcc */
  58.     74,                            /* titlewidth */
  59.     0, 0, 0, 0};                /* unused fields */
  60.  
  61. extern struct Point sfppoint, sfgpoint;
  62.  
  63. void vmxfer(cnr *cp)
  64. {
  65.  
  66. /* In xfer mode, the Mac program acts as a slave to VM/370,
  67.    executing each command from VM (a command may include data
  68.    to be processed) and returning a return code or data block. */
  69.  
  70. register short i;            /* loop counter */
  71. short rmax;                    /* count for uncompress loop */
  72. unsigned char rchk[5];        /* received checksum string */
  73. unsigned char cchk[5];        /* computed checksum string */
  74. char cmdok;                    /* if true, command is ok */
  75.  
  76. /* process a command from VM */
  77.  
  78. cp->slen = 0;
  79. if ((cp->rlen==2) && ((cp->rbuf)[0]==XFBGN) && ((cp->rbuf)[1]==XFBGN)) {
  80.     xfrst(cp);
  81.     cp->vmxbgn = 1;            /* set xfer mode */
  82.     xfdlg(0, "", "", "", "", cp);
  83.     return;
  84.     }
  85.  
  86. if (!(cp->vmxbgn)) {
  87.     (cp->sbuf)[cp->slen++] = ' ';
  88.     return;
  89.     }
  90.  
  91. if ((cp->rlen==1) && ((cp->rbuf)[0]==DC4)) {        /* subset code */
  92.     if (cp->vmxsub) {
  93.         if (cp->xdlg) SelectWindow(cp->xdlgptr);
  94.         }
  95.     else if (cp->myWindow != 0) SelectWindow(cp->myWindow);
  96.     cp->vmxsub ^= 1;
  97.     if (cp->myWindow != 0) newstat(cp);
  98.     return;
  99.     }
  100.  
  101. /* process compressed data */
  102. if ((cp->rlen > 6) && ((cp->rbuf)[0] == 0x18)) {
  103.     memcpy(cp->sbuf, cp->rbuf+1, cp->rlen-1);    /* copy data without prefix */ 
  104.     cp->cmpstate = 0;
  105.     rmax = cp->rlen-6;                            /* length without prefix or CRC */
  106.     cp->rlen = 0;
  107.     for (i=0; i < rmax; i++) datachr(&(cp->rlen), (cp->sbuf)[i], cp);
  108.     while(i < rmax+5) (cp->rbuf)[cp->rlen++] = (cp->sbuf)[i++];    /* append CRC */
  109.     }
  110.  
  111. /* verify data read is valid; if not, set cmdok FALSE */
  112.  
  113. if ((cp->rlen > 6) &  (cp->rlen < 2320)) {
  114.     (cp->rbuf)[cp->rlen] = '\0';            /* delimit received checksum */
  115.     strcpy(rchk,cp->rbuf+cp->rlen-4);        /* copy checksum */
  116.     (cp->rbuf)[cp->rlen-5] = '\0';            /* delimit data */
  117.     cp->rlen -= 5;                            /* rlen = data length */
  118.     chkdata(cp->rbuf, cp->rlen,cchk);        /* calculate data checksum */         
  119.     cmdok = (strcmp(rchk,cchk) == 0);        /* compare checksums */
  120.     }
  121. else cmdok = 0;
  122.  
  123. /*  If command is ok, return the result of attempting to execute
  124.     it. If the command is in error, just transmit a blank. */
  125.  
  126. if (cmdok) {
  127.     cp->crcok = 0;                                /* no CRC yet */
  128.     excmmd(cp);                                    /* execute command */
  129.     if (cp->crcok == 0) {                        /* append CRC if needed */
  130.         if (cp->slen == 0) cp->slen = strlen(cp->sbuf);    /* get data length */
  131.         chkdata(cp->sbuf,cp->slen,cchk);        /* get checksum */
  132.         (cp->sbuf)[cp->slen] = CD;                /* delimit checksum */
  133.         memcpy(cp->sbuf+cp->slen+1, cchk, 4);    /* append checksum */
  134.         cp->slen += 5;                            /* update length */
  135.         }
  136.     }
  137. else (cp->sbuf)[cp->slen++] = ' ';
  138. }
  139.  
  140. void chkdata(unsigned char *buf, short len, unsigned char *chk)
  141. {
  142. register unsigned char i;
  143.  
  144. /* calculate four-byte ASCII checksum for buf in chk */
  145.  
  146. sprintf(chk,"%4x",crcf(buf,len,0));
  147. for (i = 0; i < 4; i++)            /* convert blanks to zeros */
  148.     if (chk[i] == ' ') chk[i] = '0';
  149.     else chk[i] = toupper(chk[i]);
  150. }
  151.  
  152. void excmmd(cnr *cp)
  153. {
  154. register unsigned short i;
  155. i = ((cp->rbuf)[0] << 8) + (cp->rbuf)[1];
  156. switch(i) {
  157.     case 0x4f49:        /* 'OI' */
  158.         rdopen(cp);
  159.         break;
  160.     case 0x4249:        /* 'BI' */
  161.         rdopen(cp);
  162.         break;
  163.     case 0x5242:        /* 'RB' */
  164.         rdblock(cp);
  165.         break;
  166.     case 0x4349:        /* 'CI' */
  167.         rdclose(cp);
  168.         break;
  169.     case 0x4f4f:        /* 'OO' ASCII Output (old WMAC) */
  170.     case 0x414f:        /* 'AO' Alternate Output (new WMAC) */
  171.     case 0x424f:        /* 'BO' Binary Output (new WMAC) */
  172.     case 0x4d4f:        /* 'MO' MacBinary Output (new WMAC) */
  173.     case 0x4d48:        /* 'MH' MacBinary Header (new WMAC) */
  174.         wropen(cp);
  175.         break;
  176.     case 0x5742:        /* 'WB' */
  177.         wrblock(cp);
  178.         break;
  179.     case 0x434f:        /* 'CO' */
  180.         wrclose(cp);
  181.         break;
  182.     case 0x4558:        /* 'EX' */
  183.         exitcmd(cp);
  184.         break;
  185.     case 0x5652:        /* 'VR' */
  186.         verscmd(cp);
  187.         break;
  188.     case 0x5454:        /* 'TT' */
  189.         trtime(cp);
  190.         break;
  191.     case 0x584c:        /* 'XL' */
  192.         xlcmd(cp);
  193.         break;
  194.     default:
  195.         setrc(28, cp);
  196.         break;
  197.     }
  198. }
  199.  
  200. void setrc(short code, cnr *cp)
  201. {
  202. register char i;
  203. sprintf(cp->sbuf,"RC%4d",code);
  204. for (i = 2; i < 6; i++)
  205.     if ((cp->sbuf)[i] == ' ') (cp->sbuf)[i] = '0';
  206. }
  207.  
  208. void rdopen(cnr *cp)
  209. {
  210. short rdlast;
  211. register short rc;
  212. register char nomenu, rdcancel;
  213. long fsize;
  214. struct DateTimeRec fdate;
  215.  
  216. rdcancel = 0;
  217. nomenu = 0;                        /* handle menu option */
  218. rdlast = strlen(cp->rbuf+2) + 1;
  219. if ((cp->rbuf)[rdlast] == '*') {
  220.     (cp->rbuf)[rdlast] = 0;
  221.     nomenu = 1;
  222.     }
  223. cp->binxf = ((cp->rbuf)[0] == 'B');
  224. rc = -1;            /* simulate open error for menu */
  225. cp->ropen = 0;
  226. if (nomenu) {
  227.     strcpy(cp->macVName+1,currvname(cp));    /* get default volume */
  228.     (cp->macVName)[0] = strlen(cp->macVName+1);
  229.     strcpy(cp->macFName+1,cp->rbuf+2);        /* get file id */
  230.     (cp->macFName)[0] = strlen(cp->macFName+1);
  231.     rc = fsrdopen(cp->macFName+1, cp->vnum, &(cp->rfd));
  232.     }
  233. if (rc != 0) {                /* get id from user */
  234.     getrd(cp->macFName, cp);
  235.     if ((cp->macFName)[0] == 0) rdcancel = 1;
  236.     if (!rdcancel)
  237.         rc = fsrdopen(cp->macFName+1, cp->vnum, &(cp->rfd));
  238.     }
  239. if (rc != 0) {
  240.     if (!rdcancel) stoperr(300, cp);
  241.     setrc(1, cp);
  242.     return;
  243.     }
  244. if (rc == 0) cp->ropen = 1;
  245. strcpy(cp->statname,"Uploading");
  246. getinfo(&fsize, &fdate, cp);
  247. cp->filsiz = (fsize + 127) >> 7;
  248. cp->cursiz = 0;
  249. strcpy(cp->sbuf,"AT");                /* success: return file attributes */
  250. if (cp->binxf) (cp->sbuf)[0] = 'B';        /* use BT for binary transfer */
  251. sprintf(cp->sbuf+2,"%04x",cp->filsiz);    /* file size */
  252. sprintf(cp->sbuf+6,"%04d%02d%02d%02d%02d%02d",    /* date */
  253.     fdate.year,fdate.month,fdate.day,fdate.hour,
  254.     fdate.minute,fdate.second);
  255. }
  256.  
  257. void rdclose(cnr *cp)
  258. {
  259. cp->ropen = 0;
  260. if (FSClose(cp->rfd) != 0) setrc(1, cp);     /* close input file */
  261.     else {
  262.         FlushVol(0L, cp->vnum);
  263.         setrc(0, cp);
  264.     }
  265. }
  266.  
  267. void rdblock(cnr *cp)
  268. {
  269. short rc, rdlen, padlen;
  270. register short i, reccnt;
  271. unsigned char blkstr[5]; 
  272. char eof, trflg;
  273. unsigned char padchr;
  274. register unsigned char c, maxchar;
  275. unsigned long recnum, r_byte;
  276. short iaccount, dest, src;
  277. unsigned char cchk[5];            /* computed checksum string */
  278.  
  279. if (cp->kabort) {            /* set rc 11 for subset/abort */
  280.     setrc(11, cp);
  281.     cp->kabort = 0;
  282.     return;
  283.     }
  284.  
  285. /* give error 3 if block number and speed not read */
  286. if (cp->rlen < 10) {
  287.     setrc(3, cp);
  288.     return;
  289.     }
  290.  
  291. /* extract xfspeed and save */
  292. memcpy(blkstr, cp->rbuf+6, 4);
  293. blkstr[4] = '\0';
  294. cp->xfspeed = atoi(blkstr);
  295.  
  296. /* extract block number and convert to record */
  297. memcpy(blkstr, cp->rbuf+2, 4);
  298. blkstr[4] = '\0';
  299. recnum = atol(blkstr);            /* record = block * 18 */
  300. recnum *= 18;
  301.  
  302. /* read 18 records (2304 bytes) or less at end of file */
  303. strcpy(cp->sbuf,"DB");        /* store data block prefix */
  304. typstat(cp);
  305.  
  306. r_byte = recnum << 7;            /* byte offset = record * 128 */
  307. rc = SetFPos(cp->rfd, 1, r_byte);    /* position for read */
  308. if (rc == eofErr) {                /* rc 1 for eof */
  309.     setrc(1, cp);
  310.     return;
  311.     }
  312. else if (rc != 0) {
  313.     stoperr(301, cp);
  314.     setrc(8, cp);
  315.     return;
  316.     }
  317. r_byte = 2304;                    /* read next 2304 bytes of data */
  318. rc = FSRead(cp->rfd, (long *)&r_byte, cp->sbuf+2);
  319. if ((rc != eofErr) && (rc != 0)) {    /* check for errors */
  320.     stoperr(301, cp);
  321.     setrc(9, cp);
  322.     return;
  323.     }
  324. if (r_byte == 0) {        /* assume eof if zero bytes read */
  325.     setrc(1, cp);
  326.     return;
  327.     }
  328. rdlen = r_byte;
  329. padlen = 128 - (rdlen % 128);    /* pad to a multiple of 128 */
  330. if (cp->binxf) padchr = 0;
  331. else padchr = CPMEOF;
  332. if (padlen < 128) {
  333.     rdlen += 2;
  334.     for (i=0; i < padlen; i++) (cp->sbuf)[rdlen++] = padchr;
  335.     rdlen -= 2;
  336.     }
  337. if (cp->binxf) cp->slen = rdlen+2;
  338. else (cp->sbuf)[rdlen+2] = '\0';
  339. reccnt = rdlen >> 7;    /* no. of 128-byte blocks */
  340. if (reccnt > 0) cp->cursiz = recnum + reccnt;
  341.  
  342. /* For TCP/IP binary transfer, quoting must be inserted for the IAC
  343.    character (X'FF') by replacing each IAC by two of them  */
  344.  
  345. if (cp->binxf && cp->tcpflg) {
  346.     /* append CRC before changing data */
  347.     chkdata(cp->sbuf,cp->slen,cchk);        /* get checksum */
  348.     (cp->sbuf)[cp->slen] = CD;                /* delimit checksum */
  349.     memcpy(cp->sbuf+cp->slen+1, cchk, 4);    /* append checksum */
  350.     cp->slen += 5;                        /* update length */
  351.     cp->crcok = 1;                        /* tell mainline CRC done */
  352.  
  353.     /* now handle IAC characters */
  354.     iaccount = 0;
  355.     for (i=2; i < cp->slen; i++) { 
  356.         if ((cp->sbuf)[i] == IAC) iaccount++;
  357.         }
  358.     if (iaccount == 0) return;
  359.     dest = cp->slen + iaccount - 1;
  360.     src = cp->slen - 1;
  361.     cp->slen += iaccount;
  362.     while (iaccount > 0) {
  363.         (cp->sbuf)[dest--] = c = (cp->sbuf)[src--];
  364.         if (c == IAC) {
  365.             (cp->sbuf)[dest--] = IAC;
  366.             iaccount--;
  367.             }
  368.         }
  369.     return;
  370.     }
  371.     
  372. if (cp->binxf) return;
  373.  
  374. /* translate invalid characters to "|" and display file
  375.    data on terminal */
  376.  
  377. eof = trflg = 0;
  378. rdlen += 2;
  379. /* versions of RMAC/WMAC which issue the XL command also support Macintosh
  380.    extended ASCII, and can translate characters through X'DE' */
  381. if (cp->xlflag) maxchar = 222;
  382. else maxchar = 126;
  383. for (i = 2; i < rdlen; i++) {
  384.     if (eof) {
  385.         (cp->sbuf)[i] = '\0';
  386.         break;
  387.         }
  388.     c = (cp->sbuf)[i];
  389.     switch (c) {
  390.         case TAB:
  391.         case LF:
  392.         case FF:
  393.                     break;
  394.         case CR:
  395.                     (cp->sbuf)[i] = VT;
  396.                     break;
  397.         case CPMEOF:
  398.                     eof = 1;
  399.                     break;
  400.         case DEL:
  401.                     trflg = 1;
  402.                     (cp->sbuf)[i] = '|';
  403.                     break;
  404.         default:
  405.                     if ((c < 32) || (c > maxchar)) {
  406.                         trflg = 1;
  407.                         (cp->sbuf)[i] = '|';
  408.                         }
  409.                     break;
  410.         }
  411.     }
  412.  
  413. if (trflg) stoperr(302, cp);
  414. }
  415.  
  416. void typstat(cnr *cp)            /* output transfer status */
  417. {
  418. unsigned char tofrom[5];
  419. unsigned percent, min, sec, ovrhead;
  420. long lcvt, lchar, curbytes, totbytes;
  421.  
  422. curbytes = (long)(cp->cursiz) << 7;
  423. totbytes = (long)(cp->filsiz) << 7;
  424. lcvt = cp->cursiz;
  425. percent = (lcvt*100)/cp->filsiz;
  426. if (cp->prtxf) {
  427.     sprintf(cp->statbuf, "%s '%s'", cp->statname, cp->macFName+1);
  428.     }
  429. else {
  430.     if ((cp->statname)[0] == 'D') strcpy(tofrom,"to");
  431.     else strcpy(tofrom,"from");
  432.     sprintf(cp->statbuf,"%s '%s' %s '%s'", cp->statname, cp->macFName+1,
  433.         tofrom, cp->macVName+1);
  434.     }
  435. sprintf(cp->prtbuf2,"%ld/%ld (%d%%)", curbytes, totbytes, percent);
  436. if (cp->xfspeed == 0) {
  437.     sprintf(cp->prtbuf3,"");
  438.     sprintf(cp->prtbuf4,"??:??");
  439.     }
  440. else {
  441.     ovrhead = (cp->filsiz-cp->cursiz+7)/8;    /* no. of rb/wb cmmds. */
  442.     if ((cp->statname)[0] == 'D') ovrhead *= 30;
  443.                              else ovrhead *= 26;
  444.     lchar = cp->filsiz - cp->cursiz;    /* get total character count */
  445.     lchar <<= 7;
  446.     lchar += ovrhead;        /* plus overhead */
  447.     lcvt = cp->xfspeed;
  448.     sec = lchar/lcvt;        /* get seconds */
  449.     min = sec / 60;
  450.     sec = sec % 60;
  451.     sprintf(cp->prtbuf3,"%d",cp->xfspeed);
  452.     sprintf(cp->prtbuf4,"%d:%02d",
  453.             min,sec);
  454.     }
  455. xfdlg(1,cp->statbuf,cp->prtbuf2,cp->prtbuf3,cp->prtbuf4, cp);
  456. }
  457.  
  458. void wropen(cnr *cp)
  459. {
  460. unsigned char cvtbuff[5];
  461. short rdlast;
  462. register short rc;
  463. unsigned short i;
  464. register unsigned long freeBytes, totBytes;
  465. VolumeParam pb;
  466. struct DateTimeRec fdate;
  467. int year, month, day, hour, minute, second;
  468. char mhcmd;
  469. HFileParam pbf;
  470. GrafPtr gp;
  471. static unsigned char listingft1[] = "listing";
  472. static unsigned char listingft2[] = "LISTING";
  473. static long minus1 = -1;
  474.  
  475. mhcmd = ((cp->rbuf)[0] == 'M') && ((cp->rbuf)[1] == 'H');
  476. if (mhcmd) {
  477.     memcpy(&(cp->mh), cp->rbuf+2, 128);    /* save header */
  478.     if ((cp->mh.fnlen == 0) || (cp->mh.fnlen > 63)) {
  479.         stoperr(303, cp);
  480.         setrc(64, cp);        /* check for valid fn length */
  481.         return;
  482.         }
  483.     p2cstr(&(cp->mh.fnlen));    /* convert filename to C format */
  484.     cp->mbdsize = chartolong(cp->mh.dataln);  /* get lengths of forks */
  485.     cp->mbrsize = chartolong(cp->mh.rscln);
  486.     cp->mbdbmax = (cp->mbdsize+127) >> 7;    /* get block counts */
  487.     cp->mbrbmax = (cp->mbrsize+127) >> 7;
  488.     cp->mbdextra = (cp->mbdbmax << 7) - cp->mbdsize;    /* get padding counts */
  489.     cp->mbrextra = (cp->mbrbmax << 7) - cp->mbrsize;
  490.     }
  491. else {            /* if not MH, get info. from rbuf */
  492.                     /* set nomenu or prtxf flag */
  493.     cp->nomenu = 0;
  494.     cp->prtxf = 0;
  495.     rdlast = strlen(cp->rbuf+20) + 19;
  496.     if ((cp->rbuf)[rdlast] == '*') {
  497.         (cp->rbuf)[rdlast] = 0;
  498.         cp->nomenu = 1;
  499.         }
  500.     else if ((cp->rbuf)[rdlast] == '.') {
  501.         (cp->rbuf)[rdlast] = 0;
  502.         cp->prtxf = 1;
  503.         }
  504.                     /* get file size */
  505.     memcpy(cvtbuff, cp->rbuf+2, 4);
  506.     cvtbuff[4] = '\0';
  507.     sscanf(cvtbuff, "%x", &(cp->filsiz));
  508.                     /* get file date and time */
  509.     sscanf(cp->rbuf+6, "%4d%2d%2d%2d%2d%2d",
  510.             &year, &month, &day, &hour,
  511.             &minute, &second);
  512.     fdate.year = year;
  513.     fdate.month = month;
  514.     fdate.day = day;
  515.     fdate.hour = hour;
  516.     fdate.minute = minute;
  517.     fdate.second = second;
  518.     fdate.dayOfWeek = 0;
  519.     cp->wdate = fdate;
  520.     }
  521.  
  522. if (((cp->rbuf)[0] == 'M') && ((cp->rbuf)[1] == 'O')) {
  523.                 /* finish MO processing */
  524.     cp->binxf = cp->mbinxf = 1;
  525.     cp->prtxf = 0;
  526.     strcpy(cp->sbuf,"MT");
  527.     return;
  528.     }
  529.                 /* set binxf, mbinxf for all but "MO" */
  530. if ((cp->rbuf)[1] == 'O') {
  531.     cp->binxf = ((cp->rbuf)[0] == 'B');
  532.     cp->mbinxf = 0;
  533.     }
  534.  
  535.                 /* get file id to use */
  536. if (!(cp->prtxf)) {
  537.     if (cp->nomenu) {
  538.         strcpy(cp->macVName+1, currvname(cp));
  539.         (cp->macVName)[0] = strlen(cp->macVName+1);
  540.         if (mhcmd) strcpy(cp->macFName+1, &(cp->mh.fnlen));
  541.         else strcpy(cp->macFName+1,cp->rbuf+20);
  542.         (cp->macFName)[0] = strlen(cp->macFName+1);
  543.         /* check if file already exists */
  544.         c2pstr(cp->macFName+1);
  545.         rc = FSOpen(cp->macFName+1, cp->vnum, &(cp->wfd));
  546.         p2cstr(cp->macFName+1);
  547.         if (rc == 0) {
  548.                 setrc(1, cp);
  549.                 FSClose(cp->wfd);
  550.                 FlushVol(0L, cp->vnum);
  551.                 return;
  552.                 }
  553.         }
  554.     else if (mhcmd) getwr(&(cp->mh.fnlen), cp->macFName, cp);
  555.                 else getwr(cp->rbuf+20, cp->macFName, cp);
  556.     if (strlen(cp->macFName) == 0) {
  557.         setrc(5, cp);
  558.         return;
  559.         }
  560.     }
  561. else {
  562.     strcpy(cp->macFName+1, cp->rbuf+20);
  563.     (cp->macFName)[0] = strlen(cp->macFName+1);
  564.     i = (cp->macFName)[0] - strlen(listingft1);
  565.     if (i >= 2)
  566.         cp->prtcc = (strcmp(listingft1, cp->macFName+i+1) == 0) ||
  567.                       (strcmp(listingft2, cp->macFName+i+1) == 0);
  568.     else
  569.         cp->prtcc = 0;
  570.     prtwrite(&minus1, 0L, cp);    /* prtwrite initialization */
  571. }
  572.     
  573. /* now ready to use file id */
  574.  
  575. if (!(cp->prtxf)) {
  576.     /* initialize for file calls */
  577.     memset(&pbf, 0, sizeof(HFileParam));
  578.  
  579.     /* delete any existing file */
  580.     pbf.ioNamePtr = (StringPtr)(cp->macFName);
  581.     pbf.ioVRefNum = cp->vnum;
  582.     PBDelete((ParmBlkPtr)&pbf, 0);
  583.  
  584.     /* create new file */
  585.     rc = PBCreate((ParmBlkPtr)&pbf, 0);
  586.     if (rc != 0) {
  587.         stoperr(303, cp);
  588.         setrc(2, cp);
  589.         return;
  590.         }
  591.  
  592.     /* set finder info */
  593.     rc = PBGetFInfo((ParmBlkPtr)&pbf, 0);
  594.     if (rc != 0) {
  595.         stoperr(303, cp);
  596.         setrc(2, cp);
  597.         return;
  598.         }
  599.                         /* set finder flags */
  600.     if (cp->mbinxf) {
  601.         i = cp->mh.flags;
  602.         i <<= 8;
  603.         pbf.ioFlFndrInfo.fdFlags &= 0x00ff;
  604.         pbf.ioFlFndrInfo.fdFlags |= i;
  605.         pbf.ioFlFndrInfo.fdFlags &= 0xf8ff;
  606.         }
  607.     else pbf.ioFlFndrInfo.fdFlags &= 0xfeff;
  608.                         /* set type and creator */
  609.     if (cp->mbinxf) {
  610.         memcpy(&pbf.ioFlFndrInfo.fdType, cp->mh.ftyp, 4);
  611.         memcpy(&pbf.ioFlFndrInfo.fdCreator, cp->mh.fcreat, 4);
  612.         }
  613.     else {
  614.         pbf.ioFlFndrInfo.fdType = 'TEXT';
  615.         pbf.ioFlFndrInfo.fdCreator = cp->cs.text_creator;
  616.         }
  617.     rc = PBSetFInfo((ParmBlkPtr)&pbf, 0);
  618.     if (rc != 0) {
  619.         stoperr(303, cp);
  620.         setrc(2, cp);
  621.         return;
  622.         }
  623.  
  624.     /* open data fork */
  625.     memset(&pbf, 0, sizeof(HFileParam));
  626.     pbf.ioNamePtr = (StringPtr)(cp->macFName);
  627.     pbf.ioVRefNum = cp->vnum;
  628.     pbf.filler1 = fsWrPerm;        /* ioPermssn */
  629.     rc = PBOpen((ParmBlkPtr)&pbf, 0);
  630.     if (rc != 0) {
  631.         stoperr(303, cp);
  632.         setrc(2, cp);
  633.         return;
  634.         }
  635.     else cp->wfd = pbf.ioFRefNum; 
  636.  
  637.     /* open resource fork if MacBinary */
  638.     if (cp->mbinxf) {
  639.         rc = PBOpenRF((ParmBlkPtr)&pbf, 0);
  640.         if (rc != 0) {
  641.             stoperr(303, cp);
  642.             setrc(2, cp);
  643.             return;
  644.             }
  645.         else cp->wfd_r = pbf.ioFRefNum; 
  646.         }
  647.     }
  648. else {
  649.     if (hPrint == 0) {
  650.         stoperr(305, cp);
  651.         setrc(2, cp);
  652.         return;
  653.         }
  654.     arrowcursor();
  655.     if (prtinit == 0) {
  656.         PrOpen();
  657.         PrintDefault(hPrint);
  658.         prtinit = 1;
  659.         }
  660.     if (!PrJobDialog(hPrint)) {
  661.         setrc(5, cp);
  662.         return; 
  663.         }
  664.     cp->myFirst = (*hPrint)->prJob.iFstPage;
  665.     cp->myLast = (*hPrint)->prJob.iLstPage;
  666.     (*hPrint)->prJob.iFstPage = 1;
  667.     (*hPrint)->prJob.iLstPage = 999;
  668.     if (cp->myFirst < 1) cp->myFirst = 1;
  669.     if (cp->myLast < cp->myFirst) cp->myLast = 999;
  670.  
  671.     GetPort(&gp);
  672.     setdoctitle(cp->macFName+1);
  673.     cp->prtport = PrOpenDoc(hPrint, 0L, 0L);
  674.     SetPort(gp);
  675.     cp->prdocopen = 1;        /* document now open */
  676.     }
  677. cp->wopen = 1;
  678. if (cp->binxf && (!(cp->mbinxf))) strcpy(cp->sbuf,"BT");
  679. else setrc(0, cp);
  680. if (cp->prtxf) strcpy(cp->statname, "Printing"); 
  681. else strcpy(cp->statname,"Downloading");
  682. if (!(cp->prtxf)) {
  683.     pb.ioCompletion = 0;
  684.     pb.ioNamePtr    = 0;
  685.     pb.ioVRefNum    = cp->vnum;
  686.     pb.ioVolIndex = 0;
  687.     PBGetVInfo((ParmBlkPtr)&pb, 0);
  688.     freeBytes = pb.ioVFrBlk * pb.ioVAlBlkSiz;
  689.     totBytes = (long)(cp->filsiz) << 7;
  690.     if (freeBytes < totBytes) {
  691.         totBytes = (totBytes - freeBytes + 1023) >> 10;
  692.         dFullAlt((short)totBytes, cp);
  693.         FSClose(cp->wfd);
  694.         if (cp->mbinxf) FSClose(cp->wfd_r);
  695.         c2pstr(cp->macFName+1);
  696.         FSDelete(cp->macFName+1, cp->vnum);
  697.         p2cstr(cp->macFName+1);
  698.         setrc(99, cp);
  699.         return;
  700.         }
  701.     }
  702. cp->cursiz = 0;
  703. typstat(cp);
  704. }
  705.  
  706. void wrclose(cnr *cp)
  707. {
  708. short rc1, rc2;
  709.  
  710. cp->wopen = 0;
  711. if (!(cp->prtxf)) {
  712.     rc1 = FSClose(cp->wfd);
  713.     if (cp->mbinxf) rc2 = FSClose(cp->wfd_r);
  714.     else rc2 = 0;
  715.     if ((rc1 != 0) || (rc2 != 0)) {
  716.         FlushVol(0L, cp->vnum);
  717.         stoperr(304, cp);
  718.         setrc(1, cp);
  719.         }
  720.     else {
  721.         rc1 = settime(&(cp->wdate), &(cp->mh), cp);
  722.         setrc(rc1, cp);
  723.         FlushVol(0L, cp->vnum);
  724.         }
  725.     }
  726. else setrc(xfprtclose(cp), cp);
  727. }
  728.  
  729. int xfprtclose(cnr *cp)
  730. {
  731. int rc;
  732. TPrStatus prStatus;
  733. static long minus3 = -3;
  734. GrafPtr gp;
  735.  
  736. prtwrite(&minus3, 0L, cp);        /* termination call */
  737. GetPort(&gp);
  738. if (cp->prpgopen) {
  739.     SetPort((GrafPtr)(cp->prtport));
  740.     PrClosePage(cp->prtport);
  741.     }
  742. if (cp->prdocopen) {
  743.     SetPort((GrafPtr)(cp->prtport));
  744.     PrCloseDoc(cp->prtport);
  745.     if (((*hPrint)->prJob.bJDocLoop == bSpoolLoop) && (PrError() == noErr))
  746.         PrPicFile(hPrint, 0L, 0L, 0L, &prStatus);
  747.     if (PrError() != noErr) {
  748.         stoperr(305, cp);
  749.         rc = 1;
  750.         }
  751.     else rc = 0;
  752.     }
  753. else rc = 0;
  754. SetPort(gp);
  755. cp->prtxf = cp->prpgopen = cp->prdocopen = cp->prfileinit = 0;
  756. return(rc);
  757. }
  758.  
  759. void wrblock(cnr *cp)
  760. {
  761. register short i, reccnt;
  762. register short padlen;
  763. short typlen, bufwrite();
  764. unsigned char blkstr[5], c;
  765. unsigned long recnum, w_byte;
  766. OSErr rc;
  767.  
  768. if (cp->kabort) {            /* set rc 11 for subset/abort */
  769.     setrc(11, cp);
  770.     cp->kabort = 0;
  771.     return;
  772.     }
  773.  
  774. /* rbuf should contain: WBnnnnssssxxxx..., where "nnnn" is
  775.    the block number, "ssss" is the transfer speed in cps,
  776.    and "xxxx..." is the data to write. */
  777.  
  778. /* give error 3 if block number and speed not read */
  779. if (cp->rlen < 10) {
  780.     setrc(3, cp);
  781.     return;
  782.     }
  783.  
  784. /* translate SO, VT to CR, LF */
  785.  
  786. typlen = cp->rlen - 10;
  787. if (!(cp->binxf)) for (i=0; i < typlen; i++) {
  788.     c = (cp->rbuf)[i+10];
  789.     switch (c) {
  790.         case CPMEOF:    /* ignore EOF char */
  791.                     break;
  792.         case SO:        /* SO is translated CR */
  793.                     (cp->rbuf)[i+10] = CR;
  794.                     break;
  795.         case VT:        /* VT is translated LF */
  796.                     (cp->rbuf)[i+10] = LF;
  797.                     break;
  798.         case FF:
  799.                     break;
  800.         default:
  801.                     break;
  802.                 }
  803.         }
  804.  
  805. /* extract xfspeed and save */
  806. memcpy(blkstr, cp->rbuf+6, 4);
  807. blkstr[4] = '\0';
  808. cp->xfspeed = atoi(blkstr);
  809.  
  810. /* extract block number and convert to record */
  811. memcpy(blkstr, cp->rbuf+2, 4);
  812. blkstr[4] = '\0';
  813. recnum = atol(blkstr);            /* record = block * 18 */
  814. recnum *= 18;
  815.  
  816. /* assume eof if < 2304 bytes to write; pad with EOF char
  817.    to make a multiple of 128 bytes */
  818.  
  819. padlen = 128 - ((cp->rlen-10) % 128);
  820. if (cp->binxf) {
  821.     if (padlen < 128) reccnt = (padlen+cp->rlen-10) >> 7;
  822.     else reccnt = (cp->rlen-10) >> 7;
  823.     }
  824. else {
  825.     if (padlen < 128)
  826.         for (i=0; i < padlen; i++) (cp->rbuf)[cp->rlen++] = CPMEOF;
  827.     reccnt = (cp->rlen-10) >> 7; /* divide by 128 to get block count */
  828.     }
  829.  
  830. /* return now if no blocks to write (should only happen at eof) */
  831.  
  832. if (reccnt == 0) {
  833.     setrc(0, cp);
  834.     return;
  835.     }
  836.  
  837. /* for a text file, delete trailing EOF characters */
  838.  
  839. if (!(cp->binxf)) {
  840.     cp->rlen--;            /* convert length to rbuf offset */
  841.     while (cp->rlen >= 10) {
  842.         if ((cp->rbuf)[cp->rlen] != CPMEOF) break;
  843.         cp->rlen--;
  844.         }
  845.     cp->rlen++;        /* convert back to length */
  846.     if (cp->rlen == 10) {    /* return if only EOF characters */
  847.         setrc(0, cp);
  848.         return;
  849.         }
  850.     }
  851.  
  852. /* write data to disk. give return code 4 for an error */
  853.  
  854. if ((!(cp->mbinxf)) && (!(cp->prtxf))) {
  855.     w_byte = recnum << 7;          /* get byte offset */
  856.     rc = SetFPos(cp->wfd, 1, w_byte);
  857.     if (rc != 0) {
  858.         stoperr(304, cp);
  859.         setrc(4, cp);
  860.         return;
  861.         }
  862.     }
  863. w_byte = cp->rlen-10;
  864. if (cp->mbinxf) rc = mbwrite((long *)&w_byte, cp->rbuf+10, recnum, cp);
  865. else if (cp->prtxf) rc = prtwrite((long *)&w_byte, cp->rbuf+10, cp);
  866.      else rc = FSWrite(cp->wfd, (long *)&w_byte, cp->rbuf+10);
  867. if ((rc != 0) || (w_byte != cp->rlen-10)) {
  868.     if (cp->prtxf) stoperr(305, cp);
  869.     else stoperr(304, cp);
  870.     setrc(5, cp);
  871.     return;
  872.     }
  873. setrc(0, cp);
  874. cp->cursiz = recnum + reccnt;
  875. typstat(cp);
  876. }
  877.  
  878. void exitcmd(cnr *cp)        /* exit command */
  879. {
  880. setrc(0, cp);
  881. xfrst(cp);
  882. }
  883.  
  884. void verscmd(cnr *cp)        /* return version info */
  885. {
  886. strcpy(cp->sbuf,"VIM0231");        /* Macintosh 3270 version 2.31 */
  887.                 /* append national language name */
  888. strcat(cp->sbuf, ":");
  889. strcat(cp->sbuf, cp->csnlname);
  890. }
  891.  
  892. void xlcmd(cnr *cp)        /* return national language translation info. */
  893. {
  894. unsigned char *sptr;
  895. register short i, x, j;
  896.  
  897. cp->xlflag = 1;
  898. strcpy(cp->sbuf, "XI");            /* translation info */
  899. sptr = cp->sbuf+2;
  900. if (cp->nl_handle != 0) {
  901.     for (i=0; i < 256; i++) {
  902.         x = (cp->nltab)[i];
  903.         if (x != i) {
  904.             sprintf(sptr, "%02x%02x", i, x);
  905.             for (j=0; j < 4; j++) {
  906.                 sptr[j] = toupper(sptr[j]);
  907.                 }
  908.             sptr += 4;
  909.             }
  910.         }
  911.     }
  912. }
  913.  
  914. void trtime(cnr *cp)        /* read and display new transfer time */
  915. {
  916. unsigned char blkstr[5];
  917.  
  918. /* extract xfspeed and save */
  919. memcpy(blkstr, cp->rbuf+2, 4);
  920. blkstr[4] = '\0';
  921. cp->xfspeed = atoi(blkstr);
  922.  
  923. /* display new status */
  924. typstat(cp);
  925.  
  926. /* return normal rc */
  927. setrc(0, cp);
  928. }
  929.  
  930. void getrd(unsigned char *macname, cnr *cp)
  931. {
  932. Point where;
  933. pascal Boolean (*fileFilter) ();
  934. register short numTypes;
  935. SFTypeList typeList;
  936. DlgHookProcPtr dlgHook;
  937. SFReply reply;
  938. VolumeParam pbrec;
  939. register VolumeParam * _pbrec;
  940.  
  941. _pbrec = &pbrec;
  942. where = sfgpoint;
  943. dlgHook = 0;
  944. fileFilter = onlydata;
  945. numTypes = -1;
  946. arrowcursor();
  947. SFGetFile(where, "\p", fileFilter, numTypes,
  948.     typeList, dlgHook, &reply);
  949. macname[0] = macname[1] = '\0';
  950. if (reply.good == 0) return;
  951. macname[0] = reply.fName[0];
  952. strcpy(macname+1, p2cstr(&reply.fName));
  953. cp->vnum = reply.vRefNum;
  954.  
  955. pbrec.ioCompletion = 0;
  956. pbrec.ioVRefNum = cp->vnum;
  957. pbrec.ioVolIndex = 0;
  958. pbrec.ioNamePtr = (StringPtr)(cp->macVName);
  959. PBGetVInfo((ParmBlkPtr)_pbrec, 0);
  960. (cp->macVName)[1+(cp->macVName)[0]] = '\0';
  961. }
  962.  
  963. pascal Boolean onlydata(FileParam *_pb)
  964. {
  965. if (_pb->ioFlLgLen == 0L) return(0x100);
  966.     else return(0);
  967. }
  968.  
  969. void getwr(unsigned char *suggid, unsigned char *macname, cnr *cp)
  970. {
  971. Point where;
  972. DlgHookProcPtr dlgHook;
  973. SFReply reply;
  974. VolumeParam pbrec;
  975. VolumeParam * _pbrec;
  976.  
  977. _pbrec = &pbrec;
  978. where = sfppoint;
  979. dlgHook = 0;
  980. arrowcursor();
  981. c2pstr(suggid);
  982. SFPutFile(where, "\pSave downloaded file as:",
  983.     suggid, dlgHook, &reply);
  984. p2cstr(suggid);
  985. macname[0] = macname[1] = '\0';
  986. if (reply.good == 0) return;
  987. macname[0] = reply.fName[0];
  988. strcpy(macname+1, p2cstr(&reply.fName));
  989. cp->vnum = reply.vRefNum;
  990.  
  991. pbrec.ioCompletion = 0;
  992. pbrec.ioVRefNum = cp->vnum;
  993. pbrec.ioVolIndex = 0;
  994. pbrec.ioNamePtr = (StringPtr)cp->macVName;
  995. PBGetVInfo((ParmBlkPtr)_pbrec, 0);
  996. (cp->macVName)[1+(cp->macVName)[0]] = '\0';
  997. }
  998.  
  999. unsigned char *currvname(cnr *cp)
  1000. {
  1001. VolumeParam pb;
  1002. OSErr rc;
  1003.  
  1004. pb.ioCompletion = 0;
  1005. pb.ioNamePtr = (StringPtr)(cp->rtnvol);
  1006. pb.ioVRefNum = cp->vnum;
  1007. pb.ioVolIndex = 0;
  1008. rc = PBGetVInfo((ParmBlkPtr)&pb, 0);
  1009. if (rc == 0) p2cstr(cp->rtnvol);
  1010. else {
  1011.     GetVol(cp->rtnvol, &(cp->vnum));
  1012.     p2cstr(cp->rtnvol);
  1013.     }
  1014. return(cp->rtnvol);
  1015. }
  1016.  
  1017. void getinfo(long *fsize, struct DateTimeRec *fdate, cnr *cp)
  1018. {
  1019. FileParam fblk;
  1020. register FileParam * _fblk;
  1021.  
  1022. _fblk = &fblk;
  1023. fblk.ioCompletion = 0;
  1024. fblk.ioNamePtr = (StringPtr)(cp->macFName);
  1025. fblk.ioVRefNum = cp->vnum;
  1026. fblk.ioFVersNum = 0;
  1027. fblk.ioFDirIndex = 0;
  1028. PBGetFInfo((ParmBlkPtr)_fblk,0);
  1029. *fsize = fblk.ioFlLgLen;
  1030. Secs2Date(fblk.ioFlMdDat, fdate);
  1031. }
  1032.  
  1033. OSErr settime(struct DateTimeRec *fdate, struct mbhdr *mh, cnr *cp)
  1034. {
  1035. FileParam fblk;
  1036. long crsecs, mdsecs;
  1037. OSErr rc;
  1038.  
  1039. memset(&fblk, 0, sizeof(FileParam));
  1040. fblk.ioNamePtr = (StringPtr)(cp->macFName);
  1041. fblk.ioVRefNum = cp->vnum;
  1042. rc = PBGetFInfo((ParmBlkPtr)&fblk,0);
  1043. if (rc != 0) return(rc+200);
  1044. Date2Secs(fdate, &fblk.ioFlMdDat);
  1045. Date2Secs(fdate, &fblk.ioFlCrDat);
  1046. if (cp->mbinxf) {
  1047.     crsecs = chartolong(mh->crdate);
  1048.     mdsecs = chartolong(mh->mddate);
  1049.     if ((crsecs != 0) && (mdsecs != 0)) {
  1050.         fblk.ioFlMdDat = mdsecs;
  1051.         fblk.ioFlCrDat = crsecs;
  1052.         }
  1053.     }
  1054. rc = PBSetFInfo((ParmBlkPtr)&fblk,0);
  1055. if (rc != 0) return(rc+300);
  1056. else return(0);
  1057. }
  1058.  
  1059. void xfrst(cnr *cp)
  1060. {
  1061. short rc;
  1062. if (cp->prtxf) xfprtclose(cp);
  1063. else {
  1064.     if (cp->ropen) if (FSClose(cp->rfd) == 0) FlushVol(0L, cp->vnum);
  1065.     if (cp->wopen) {
  1066.         rc = FSClose(cp->wfd);
  1067.         if ((rc == 0)  && cp->mbinxf) rc = FSClose(cp->wfd_r);
  1068.         if (rc == 0) FlushVol(0L, cp->vnum);
  1069.         }
  1070.     }
  1071. xfdlg(2, "", "", "", "", cp);
  1072. xfinit(cp);
  1073. }
  1074.  
  1075. void xfinit(cnr *cp)
  1076. {
  1077. cp->vmxsub = cp->vmxbgn = 0;
  1078. cp->kabort = 0;
  1079. cp->ropen = cp->wopen = 0;
  1080. cp->xfspeed = 0;
  1081. cp->xdlg = 0;
  1082. cp->prtxf = 0;
  1083. cp->prdocopen = 0;
  1084. cp->prpgopen = 0;
  1085. cp->prfileinit = 0;
  1086. cp->xlflag = 0;
  1087. if (cp->myWindow != 0) {
  1088.     newstat(cp);
  1089.     }
  1090. }
  1091.  
  1092. void datachr(short *rdoff, unsigned char c, cnr *cp)
  1093. {
  1094. short count, max;
  1095.  
  1096. switch(cp->cmpstate) {
  1097.     case 0:                        /* normal character */
  1098.         if (c == 0x18) cp->cmpstate = 1;
  1099.         else {
  1100.             (cp->rbuf)[(*rdoff)++] = c;
  1101.             cp->prevchar = c;
  1102.             }
  1103.         break;
  1104.     case 1:                        /* after x'18' */
  1105.         if (c == 0x18) {            /* literal x'18' */
  1106.             (cp->rbuf)[(*rdoff)++] = c;
  1107.             cp->prevchar = c;
  1108.             }
  1109.         else {                        /* compression count */
  1110.             count = (c - 0x20) + 2;
  1111.             max = 2320 - (*rdoff);
  1112.             if (count > max) count = max;
  1113.             while (count > 0) {
  1114.                 (cp->rbuf)[(*rdoff)++] = cp->prevchar;
  1115.                 count--;
  1116.                 }
  1117.             }
  1118.         cp->cmpstate = 0;
  1119.         break;
  1120.     default:
  1121.         break;
  1122.     }
  1123. }
  1124.  
  1125. long chartolong(unsigned char *str)
  1126. {
  1127. union {
  1128.     unsigned char s[4];
  1129.     long l;
  1130.     } u;
  1131.  
  1132. memcpy(u.s, str, 4);
  1133. return(u.l);
  1134. }
  1135.  
  1136. OSErr mbwrite(long *count, unsigned char *data, unsigned long offset, cnr *cp)
  1137. {
  1138. long bcnt, tsize, wsize;
  1139. OSErr rc;
  1140. unsigned char * newdata;
  1141. long newcount;
  1142. long mbdbcnt, mbrbcnt, mbtotal;
  1143. long pos;
  1144.  
  1145. /* set block counts file block offset */
  1146.  
  1147. mbtotal = cp->mbdbmax + cp->mbrbmax;
  1148. if (offset > mbtotal) return(999);
  1149. if ((offset == mbtotal) && ((*count) != 0)) return(998);
  1150.  
  1151. if (offset >= cp->mbdbmax) {
  1152.     mbdbcnt = 0;
  1153.     mbrbcnt = mbtotal - offset;
  1154.     }
  1155. else {
  1156.     mbdbcnt = cp->mbdbmax - offset;
  1157.     mbrbcnt = cp->mbrbmax;
  1158.     }
  1159.  
  1160. bcnt = ((*count) + 127) >> 7;
  1161. if (bcnt > (mbdbcnt + mbrbcnt)) bcnt = mbdbcnt + mbrbcnt;
  1162. if (bcnt == 0) return(0);
  1163. newdata = data;        /* init. data for resource fork */
  1164. newcount = (*count);
  1165. if (mbdbcnt > 0) {
  1166.     if (bcnt <= mbdbcnt) {    /* all blocks in data fork */
  1167.         wsize = bcnt << 7;
  1168.         if (bcnt == mbdbcnt) wsize -= cp->mbdextra;
  1169.         tsize = wsize;
  1170.         if (wsize <= (*count)) {
  1171.             pos = (cp->mbdbmax - mbdbcnt) << 7;
  1172.             rc = SetFPos(cp->wfd, 1, pos); 
  1173.             if (rc == 0) rc = FSWrite(cp->wfd, &wsize, data);
  1174.             }
  1175.         else rc = -999; 
  1176.         if ((rc == 0) && (wsize == tsize)) return(0);
  1177.         else {
  1178.             (*count) = 0;
  1179.             return(rc);
  1180.             }
  1181.         }
  1182.     else {                    /* blocks for resource fork too */
  1183.         wsize = mbdbcnt << 7;
  1184.         newdata = data + wsize;
  1185.         newcount = (*count) - wsize;
  1186.         wsize -= cp->mbdextra;
  1187.         tsize = wsize;
  1188.         pos = (cp->mbdbmax - mbdbcnt) << 7;
  1189.         rc = SetFPos(cp->wfd, 1, pos);
  1190.         if (rc == 0) rc = FSWrite(cp->wfd, &wsize, data);
  1191.         if ((rc == 0) && (wsize == tsize)) bcnt -= mbdbcnt;
  1192.         else {
  1193.             (*count) = 0;
  1194.             return(rc);
  1195.             }
  1196.         }
  1197.     }
  1198.  
  1199. /* all remaining blocks for resource fork */
  1200. wsize = bcnt << 7;
  1201. if (bcnt == mbrbcnt) wsize -= cp->mbrextra;
  1202. tsize = wsize;
  1203. if (wsize <= newcount) {
  1204.     pos = (cp->mbrbmax - mbrbcnt) << 7;
  1205.     rc = SetFPos(cp->wfd_r, 1, pos);
  1206.     if (rc == 0) rc = FSWrite(cp->wfd_r, &wsize, newdata);
  1207.     }
  1208. else rc = -999; 
  1209. if ((rc == 0) && (wsize == tsize)) {
  1210.     mbrbcnt -= bcnt;
  1211.     return(0);
  1212.     }
  1213. else {
  1214.     (*count) = 0;
  1215.     return(rc);
  1216.     }
  1217. }
  1218.  
  1219. OSErr prtwrite(long *count, unsigned char *addr, cnr *cp)
  1220. {
  1221. static long minus1 = -1;
  1222. static long minus2 = -2;
  1223. static long minus3 = -3;
  1224. unsigned short c, i, j;
  1225.  
  1226. if (((*count) == 0) || ((*count) < -3)) return(0);
  1227.  
  1228. if (((*count) == -1) || ((*count) == -2)) {        /* initialization calls */
  1229.     memset(cp->newline1, ' ', MAXLINEWIDTH+2);            /* -1 for new page */
  1230.     memset(cp->newline2, ' ', MAXLINEWIDTH+2);            /* -2 for new line */
  1231.     if (cp->prtcc) cp->prtlen = cp->prtlen1 = cp->prtlen2 = 0;
  1232.     else cp->prtlen = cp->prtlen1 = cp->prtlen2 = 1;
  1233.     if ((*count) == -1) cp->nextcc = '1';
  1234.     else cp->nextcc = ' ';
  1235.     return(0);
  1236.     }
  1237.  
  1238. if ((*count) == -3) {                            /* termination call */
  1239.     if (cp->prtcc) {
  1240.         if (cp->prtlen1 > 0) {
  1241.             (cp->newline1)[cp->prtlen1] = 0;
  1242.             prtline(cp->newline1, cp);
  1243.             }
  1244.         }
  1245.     else {
  1246.         if (cp->prtlen1 > 1) {
  1247.             (cp->newline1)[0] = cp->nextcc;
  1248.             cp->nextcc = '+';
  1249.             (cp->newline1)[cp->prtlen1] = 0;
  1250.             prtline(cp->newline1, cp);
  1251.             }
  1252.         if (cp->prtlen2 > 1) {
  1253.             (cp->newline2)[0] = cp->nextcc;
  1254.             cp->nextcc = '+';
  1255.             (cp->newline2)[cp->prtlen2] = 0;
  1256.             prtline(cp->newline2, cp);
  1257.             }
  1258.         }
  1259.     return(0);
  1260.     }
  1261.  
  1262. for (i = 0; i < (*count); i++) {
  1263.     c = addr[i];
  1264.     if (cp->prtcc)
  1265.         switch(c) {
  1266.             case TAB:
  1267.                 if (cp->prtlen1 < prtinfo.linewidth+1) cp->prtlen1++;
  1268.                 while ((((cp->prtlen1-1) % prtinfo.tabsize) != 0) &&
  1269.                        ((cp->prtlen1-1) < prtinfo.linewidth+1))
  1270.                     cp->prtlen1++;
  1271.                 break;
  1272.             case CR:
  1273.                 if (cp->prtlen1 == 0) (cp->newline1)[cp->prtlen1++] = ' ';
  1274.                 prtwrite(&minus3, 0L, cp);
  1275.                 prtwrite(&minus2, 0L, cp);
  1276.                 break;
  1277.             default:
  1278.                 if (cp->prtlen1 < prtinfo.linewidth+1)
  1279.                     (cp->newline1)[cp->prtlen1++] = c;
  1280.                 break;
  1281.             }
  1282.     else
  1283.         switch (c) {
  1284.             case BS:
  1285.                 if (cp->prtlen > 1) cp->prtlen--;
  1286.                 break;
  1287.             case CR:
  1288.                 if ((cp->prtlen1 == 1) && (cp->prtlen2 == 1))
  1289.                     (cp->newline1)[cp->prtlen1++] = ' ';
  1290.                 prtwrite(&minus3, 0L, cp);
  1291.                 prtwrite(&minus2, 0L, cp);
  1292.                 break;
  1293.             case LF:
  1294.                 j = cp->prtlen;
  1295.                 if ((cp->prtlen1 == 1) && (cp->prtlen2 == 1))
  1296.                     (cp->newline1)[cp->prtlen1++] = ' ';
  1297.                 prtwrite(&minus3, 0L, cp);
  1298.                 prtwrite(&minus2, 0L, cp);
  1299.                 cp->prtlen = j;
  1300.                 break;
  1301.             case FF:
  1302.                 prtwrite(&minus3, 0L, cp);
  1303.                 prtwrite(&minus1, 0L, cp);
  1304.                 cp->prtlen1 = 2;
  1305.                 break;
  1306.             case TAB:
  1307.                 if (cp->prtlen < prtinfo.linewidth+1) cp->prtlen++;
  1308.                 while ((((cp->prtlen-1) % prtinfo.tabsize) != 0) && 
  1309.                        ((cp->prtlen-1) < prtinfo.linewidth+1))
  1310.                     cp->prtlen++;
  1311.                 break;
  1312.             default:
  1313.                 if (cp->prtlen < prtinfo.linewidth) {
  1314.                     if ((cp->newline1)[cp->prtlen] == ' ') {
  1315.                         (cp->newline1)[cp->prtlen++] = c;
  1316.                         if (cp->prtlen > cp->prtlen1) cp->prtlen1 = cp->prtlen;
  1317.                         }
  1318.                     else if ((cp->newline2)[cp->prtlen] == ' ') {
  1319.                         (cp->newline2)[cp->prtlen++] = c;
  1320.                         if (cp->prtlen > cp->prtlen2) cp->prtlen2 = cp->prtlen;
  1321.                         }
  1322.                     else {
  1323.                         j = cp->prtlen;
  1324.                         prtwrite(&minus3, 0L, cp);
  1325.                         prtwrite(&minus2, 0L, cp);
  1326.                         cp->nextcc = '+';
  1327.                         cp->prtlen = j;
  1328.                         (cp->newline1)[cp->prtlen++] = c;
  1329.                         if (cp->prtlen > cp->prtlen1) cp->prtlen1 = cp->prtlen;
  1330.                         }
  1331.                     }
  1332.                 break;
  1333.             }
  1334.     }
  1335. return(0);
  1336. }
  1337.  
  1338. void prtline(unsigned char *s, cnr *cp)
  1339. {
  1340. GrafPtr gp;
  1341. char newpage;
  1342. int initskip, slen, leftoff, pglen;
  1343. int i;
  1344. unsigned char pbuff[12];
  1345.  
  1346. slen = strlen(s);
  1347. if (slen < 1) return;        /* should never happen */
  1348.  
  1349. GetPort(&gp);
  1350. SetPort((GrafPtr)(cp->prtport));
  1351.  
  1352. newpage = 0;
  1353.  
  1354. if (cp->prtcc) {
  1355.     leftoff = prtinfo.leftcc;
  1356.     pglen = prtinfo.pagelencc;
  1357.     }
  1358. else {
  1359.     leftoff = prtinfo.left;
  1360.     pglen = prtinfo.pagelength;
  1361.     }
  1362.  
  1363. if (cp->prfileinit == 0) {        /* initial call for a new file */
  1364.     cp->prfileinit = 1;
  1365.     cp->lineoffset = pglen;
  1366.     newpage = 1;
  1367.     initskip = 1;
  1368.     cp->pgnum = 0;
  1369.     maketitles(cp->tt1, cp->tt2, &(cp->tt1len), cp);
  1370.     }
  1371.  
  1372. switch(s[0]) {                /* interpret carriage control */
  1373.     case '0':
  1374.         cp->lineoffset += 2;
  1375.         initskip = cp->lineoffset - pglen;
  1376.         if (initskip > 0) newpage = 1;
  1377.         break;
  1378.     case '-':
  1379.         cp->lineoffset += 3;
  1380.         initskip = cp->lineoffset - pglen;
  1381.         if (initskip > 0) newpage = 1;
  1382.         break;
  1383.     case '+':
  1384.         break;
  1385.     case '1':
  1386.         initskip = 1;
  1387.         newpage = 1;
  1388.         break;
  1389.     default:
  1390.         cp->lineoffset ++;
  1391.         initskip = cp->lineoffset - pglen;
  1392.         if (initskip > 0) newpage = 1;
  1393.         break;
  1394.     }
  1395.  
  1396. if (newpage) {
  1397.     if (cp->prpgopen) PrClosePage(cp->prtport);
  1398.     cp->prpgopen = 0;
  1399.     cp->pgnum++;
  1400.     }
  1401. if (newpage && cp->pgnum >= cp->myFirst && cp->pgnum <= cp->myLast) {
  1402.     PrOpenPage(cp->prtport, 0L);
  1403.     cp->prpgopen = 1;
  1404.     }
  1405. if (newpage) {
  1406.     if (cp->prpgopen) {
  1407.         TextFont(prtinfo.fontnum);
  1408.         TextSize(prtinfo.pointsize);
  1409.         PicComment(155, 0, 0L);        /* line layout off */
  1410.         }
  1411.     cp->lineoffset = 0;
  1412.     if (!(cp->prtcc)) {
  1413.         memset(cp->tt1+cp->tt1len, 0x20, prtinfo.titlewidth-cp->tt1len);
  1414.         if (cp->pgnum > 999) sprintf(pbuff, "Page%4d", cp->pgnum%10000);
  1415.         else sprintf(pbuff, "Page %d", cp->pgnum);
  1416.         i = strlen(pbuff);
  1417.         memcpy(cp->tt1+prtinfo.titlewidth-i, pbuff, i); 
  1418.         i = prtinfo.titlewidth - cp->tt1len - i - strlen(cp->tt2);
  1419.         if (i >= 4) memcpy(cp->tt1+cp->tt1len+(i/2), cp->tt2, strlen(cp->tt2));
  1420.         if (cp->prpgopen) {
  1421.             MoveTo(leftoff, cp->lineoffset*prtinfo.leading+prtinfo.top);
  1422.             DrawText(cp->tt1, 0, prtinfo.titlewidth);
  1423.             }
  1424.         cp->lineoffset++;
  1425.         if (i < 4) {
  1426.             if (cp->prpgopen) {
  1427.                 MoveTo(leftoff, cp->lineoffset*prtinfo.leading+prtinfo.top);
  1428.                 DrawText(cp->tt2, 0, strlen(cp->tt2));
  1429.                 }
  1430.             cp->lineoffset++;
  1431.             }
  1432.         cp->lineoffset += prtinfo.headmarg;
  1433.         }
  1434.     cp->lineoffset += initskip-1;
  1435.     }
  1436. if (slen > 1) {
  1437.     if (cp->prpgopen) {
  1438.         MoveTo(leftoff, cp->lineoffset*prtinfo.leading+prtinfo.top);
  1439.         DrawText(s+1, 0, slen-1);
  1440.         }
  1441.     }
  1442. SetPort(gp);
  1443. }
  1444.  
  1445. void maketitles(unsigned char *tt1, unsigned char *tt2, int *tt1len, cnr *cp)
  1446. {
  1447. short tlen;
  1448. static unsigned char * days[7] = {
  1449.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1450. static unsigned char * months[12] = {
  1451.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1452.     "Aug", "Sep", "Oct", "Nov", "Dec"};
  1453. static unsigned char am[3] = "AM";
  1454. static unsigned char pm[3] = "PM";
  1455. unsigned char * timeptr;
  1456. short hours;
  1457. unsigned long datesecs;
  1458.  
  1459.                         /* first line */
  1460. memset(tt1, 0x20, prtinfo.titlewidth);
  1461. tt1[prtinfo.titlewidth] = 0;
  1462. memcpy(tt1, "File: \"", 7);
  1463. tlen = strlen(cp->macFName+1);
  1464. if (tlen > prtinfo.titlewidth-16) tlen = prtinfo.titlewidth-16;
  1465. memcpy(tt1+7, cp->macFName+1, tlen);
  1466. if (tlen < prtinfo.titlewidth-16) {
  1467.     tt1[tlen+7] = '"';
  1468.     (*tt1len) = tlen+8;
  1469.     }
  1470. else (*tt1len) = tlen+7;
  1471.                         /* second line */
  1472. Date2Secs(&(cp->wdate), &datesecs);
  1473. Secs2Date(datesecs, &(cp->wdate));
  1474. if (cp->wdate.hour < 12) timeptr = am;
  1475. else timeptr = pm;
  1476. if (cp->wdate.hour == 0) hours = 12;
  1477. else if (cp->wdate.hour > 12) hours = cp->wdate.hour - 12;
  1478. else hours = cp->wdate.hour;
  1479. sprintf(tt2, "Last Modified: %s, %s %d, %d  %d:%02d:%02d %s",
  1480. days[cp->wdate.dayOfWeek-1], months[cp->wdate.month-1], cp->wdate.day,
  1481. cp->wdate.year, hours, cp->wdate.minute, cp->wdate.second, timeptr);
  1482. }
  1483.